#include <stdio.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

#include "_font.h"
#include "_types.h"
#include "_osd.h"

/* Enables or disables debug output */
#ifdef __DEBUG
#define __D(fmt, args...) fprintf(stderr, "Font Debug: " fmt, ## args)
#else
#define __D(fmt, args...)
#endif

#define __E(fmt, args...) fprintf(stderr, "Font Error: " fmt, ## args)

static long long extra_advance_x = 0;
static long long extra_advance_y = 0;

static FT_Library library;
static FT_Face face;

static FT_Encoding encoding = FT_ENCODING_UNICODE;

static __u8 _8to5bit[256];
static __u8 _8to6bit[256];

int font_getStringWidth(unsigned char *text, unsigned int font_height) {
    FT_Error error;
    int index;
    int width = 0;
    FT_Vector pen;
    FT_Set_Char_Size(face, font_height << 6, font_height << 6, 100, 100);
    pen.x = 0;
    pen.y = 0;

    if (strlen(text) == 0) {
        return 0;
    }

    while (*text) {
        if (*text < 32 || *text > 126) {
            text++;
            continue;
        }
        FT_Set_Transform(face, NULL, &pen);
        index = FT_Get_Char_Index(face, *text);
        error = FT_Load_Glyph(face, index, 0);
        if (error) {
            __E("Failed to load glyph for character %c\n", *text);
            break;
        }
        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
            if (error) {
                __E("Failed to render glyph for character %c\n", *text);
                break;
            }
        }

        width += face->glyph->advance.x + (extra_advance_x << 6);
        pen.x += face->glyph->advance.x + (extra_advance_x << 6);
        pen.y += face->glyph->advance.y + (extra_advance_y << 6);
        text++;
    }
    width = ((width - face->glyph->advance.x) >> 6) + face->glyph->bitmap.width;
	
    return width;
}

int font_getStringHeight(char *text, int font_height) {
    FT_Error error;
    int index;
    int height = 0;
    FT_Vector pen;
    FT_Set_Char_Size(face, font_height << 6, font_height << 6, 100, 100);
    pen.x = 0;
    pen.y = 0;
    while (*text) {
        if (*text < 32 || *text > 126) {
            text++;
            continue;
        }
        FT_Set_Transform(face, NULL, &pen);
        index = FT_Get_Char_Index(face, *text);
        error = FT_Load_Glyph(face, index, 0);
        if (error) {
            __E("Failed to load glyph for character %c\n", *text);
            break;
        }
        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
            if (error) {
                __E("Failed to render glyph for character %c\n", *text);
                break;
            }
        }

        if (face->glyph->bitmap.rows > height) {
            height = face->glyph->bitmap.rows;
        }

        //width += face->glyph->advance.x + (extra_advance_x << 6);
        pen.x += face->glyph->advance.x + (extra_advance_x << 6);
        pen.y += face->glyph->advance.y + (extra_advance_y << 6);
        text++;
    }
    //width = ((width - face->glyph->advance.x) >> 6) + face->glyph->bitmap.width;
    return height;
}

/* font_string_size foi abandonada por ter funcionalidade muito duvidosa */

/*int font_string_size(char *text, int font_height, int *string_width, int *string_height) {
    FT_Error error;
    int index;
    int width = 0;
    int height = 0;
    FT_Vector pen;

    FT_Set_Char_Size(face,
            font_height << 6,
            font_height << 6,
            100,
            100);

    pen.x = 0;
    pen.y = 0;

    while (*text) {
        FT_Set_Transform(face, NULL, &pen);

        index = FT_Get_Char_Index(face, *text);

        error = FT_Load_Glyph(face, index, 0);
        if (error) {
            __E("Failed to load glyph for character %c\n", *text);
            break;
        }

        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
            if (error) {
                __E("Failed to render glyph for character %c\n", *text);
                break;
            }
        }

        width += face->glyph->bitmap.width + 1;
        if (face->glyph->bitmap.rows > height) {
            height = face->glyph->bitmap.rows;
        }

        pen.x += face->glyph->advance.x;
        pen.y += face->glyph->advance.y;
        text++;
    }

 *string_width = width;
 *string_height = height;

    return FONT_SUCCESS;
}*/

int font_init(unsigned char *filename) {
    FT_Error error;
    int i;
    static int initialized = 0;

    if (initialized) {
        return FONT_SUCCESS;
	}

    initialized = 1;

    error = FT_Init_FreeType(&library);

    if (error) {
        __E("Failed to intialize freetype library\n");
        return FONT_FAILURE;
    }

    error = FT_New_Face(library, filename, 0, &face);

    if (error) {
        __E("Failed to load font %s\n", filename);
        return FONT_FAILURE;
    }

    error = FT_Select_Charmap(face, encoding);
    if (error) {
        __E("Invalid charmap [%d]\n", encoding);
        return FONT_FAILURE;
    }

    /* Initialize the conversion arrays */
    for (i = 0; i < 256; i++)
        _8to5bit[i] = i * (1 << 5) / (1 << 8);

    for (i = 0; i < 256; i++)
        _8to6bit[i] = i * (1 << 6) / (1 << 8);

    return FONT_SUCCESS;
}

// font_render antigo (meio original...) -> abandonado em 25/06/2009

/*int font_render(char *text, int x, int y, int fade, int font_height,
        _simplescreen *scrp) {
    FT_Error error;
    int index;
    int width, height;
    int i, j, p, q, x_max, y_max, sp, dp;
    __u16 *dst;
    __u8 *src;
    FT_Vector pen;
    __u8 pixel;

    FT_Set_Char_Size(face,
            font_height << 6,
            font_height << 6,
            100,
            100);

    pen.x = x << 6;
    pen.y = (scrp->h - y) << 6;

    dst = scrp->bufp;

    while (*text) {
        FT_Set_Transform(face, NULL, &pen);

        index = FT_Get_Char_Index(face, *text);

        error = FT_Load_Glyph(face, index, 0);
        if (error) {
            __E("Failed to load glyph for character %c\n", *text);
            break;
        }

        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
            if (error) {
                __E("Failed to render glyph for character %c\n", *text);
                break;
            }
        }

        width = face->glyph->bitmap.width;
        height = face->glyph->bitmap.rows;

        x = face->glyph->bitmap_left;
        y = scrp->h - face->glyph->bitmap_top;

        x_max = x + width;
        y_max = y + height;

        src = face->glyph->bitmap.buffer;

        for (i = x, p = 0; i < x_max; i++, p++) {
            for (j = y, q = 0; j < y_max; j++, q++) {

                if (i >= scrp->w || j >= scrp->h)
                    continue;

                sp = q * width + p;
                dp = j * scrp->w + i;

                pixel = src[sp] * fade / 255;

                dst[dp] |= _8to5bit[pixel] | _8to6bit[pixel] << 5 |
                        _8to5bit[pixel] << 11;

            }
        }
        text++;

        pen.x += face->glyph->advance.x;
        pen.y += face->glyph->advance.y;

    }

    return FONT_SUCCESS;
}*/

int font_render(unsigned char *text, unsigned int x, unsigned int y, int fade, unsigned int font_height, window *winp, unsigned int r, unsigned int g, unsigned int b) {
    FT_Error error;
    int index;
    int width, height;
    int i, j, p, q, x_max, y_max, sp, dp;
    __u16 *dst;
    __u8 *src;
    FT_Vector pen;

    FT_Set_Char_Size(face, font_height << 6, font_height << 6, 100, 100);

    pen.x = x << 6;
    pen.y = (winp->h - y) << 6;

    dst = winp->rgbBuffer;

    while (*text) {
        FT_Set_Transform(face, NULL, &pen);

        index = FT_Get_Char_Index(face, *text);

        error = FT_Load_Glyph(face, index, 0);
        if (error) {
            __E("Failed to load glyph for character %c\n", *text);
            break;
        }

        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
            if (error) {
                __E("Failed to render glyph for character %c\n", *text);
                break;
            }
        }

        width = face->glyph->bitmap.width;
        height = face->glyph->bitmap.rows;

        x = face->glyph->bitmap_left;
        y = winp->h - face->glyph->bitmap_top;

        x_max = x + width;
        y_max = y + height;

        src = face->glyph->bitmap.buffer;

        __u8 *attr_dst = winp->attrBuffer;

        for (i = x, p = 0; i < x_max; i++, p++) {
            for (j = y, q = 0; j < y_max; j++, q++) {

                if (i >= winp->w || j >= winp->h)
                    continue;

                sp = q * width + p;
                dp = j * winp->w + i;

                if (!src[sp]) continue;

                dst[dp] = _8to5bit[b] | _8to6bit[g] << 5 | _8to5bit[r] << 11;

                if (dp % 2) {
                    attr_dst[dp >> 1] |= 0x07;
                } else {
                    attr_dst[dp >> 1] |= 0x70;
                }
            }

        }

        text++;
        pen.x += face->glyph->advance.x + (extra_advance_x << 6);
        pen.y += face->glyph->advance.y + (extra_advance_y << 6);

    }

    return FONT_SUCCESS;
}

void font_setExtraAdvanceX(long long extra_advanceX) {
    extra_advance_x = extra_advanceX;
}

void font_setExtraAdvanceY(long long extra_advanceY) {
    extra_advance_y = extra_advanceY;
}
